package com.cqrt.util;

import com.ty.basic.exception.message.SystemErrorCodeEnum;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.NumberToTextConverter;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class ExcelParser {

    // 日期格式（不带时间）
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
    // 日期时间格式（带时间）
    private static final SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    // 结束时间格式（当天23:59:59）
    private static final SimpleDateFormat END_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd 23:59:59");

    // 日期数值范围
    private static final double MIN_EXCEL_DATE = 0.0;
    private static final double MAX_EXCEL_DATE = 100000.0;
    // 日期阈值
    private static final int DATE_THRESHOLD = 1000;

    public static List<Map<String, String>> parseExcel(MultipartFile file) {
        List<Map<String, String>> result = new ArrayList<>();
        List<String> headers = new ArrayList<>();

        try (Workbook workbook = WorkbookFactory.create(file.getInputStream())) {
            Sheet sheet = workbook.getSheetAt(0);
            Iterator<Row> rowIterator = sheet.iterator();

            // 处理表头
            if (rowIterator.hasNext()) {
                Row headerRow = rowIterator.next();
                headers = parseHeaderRow(headerRow);
            }

            // 处理数据行
            while (rowIterator.hasNext()) {
                Row dataRow = rowIterator.next();
                Map<String, String> rowData = parseDataRow(dataRow, headers);
                result.add(rowData);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return result;
    }

    private static List<String> parseHeaderRow(Row headerRow) {
        List<String> headers = new ArrayList<>();
        for (Cell cell : headerRow) {
            headers.add(getCellValueAsString(cell));
        }
        return headers;
    }

    private static Map<String, String> parseDataRow(Row dataRow, List<String> headers) {
        Map<String, String> rowData = new LinkedHashMap<>();

        int maxCellIndex = Math.min(dataRow.getLastCellNum(), headers.size());

        for (int i = 0; i < maxCellIndex; i++) {
            Cell cell = dataRow.getCell(i, Row.MissingCellPolicy.RETURN_BLANK_AS_NULL);
            String header = headers.get(i);
            String value = cell != null ? getCellValueAsString(cell) : null;
            rowData.put(header, value);
        }

        // 处理行中缺少的列
        for (int i = maxCellIndex; i < headers.size(); i++) {
            rowData.put(headers.get(i), null);
        }

        return rowData;
    }

    /**
     * 获取单元格的字符串值（所有类型都转为字符串）
     */
    private static String getCellValueAsString(Cell cell) {
        if (cell == null) return null;

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue().trim();

            case NUMERIC:
                // 处理日期值（无论是否被标记为日期格式）
                return handleNumericCell(cell);

            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());

            case FORMULA:
                return getFormulaResultAsString(cell);

            case BLANK:
                return null;

            default:
                return cell.toString();
        }
    }


    /**
     * 判断是否为可能的Excel日期值
     * 添加阈值保护小数值不被误识别为日期
     */
    private static boolean isPossibleExcelDate(double value) {
        // 日期值通常是整数或接近整数
        double fractionalPart = value - Math.floor(value);
        boolean isNearInteger = fractionalPart < 0.000001 || fractionalPart > 0.999999;

        // 关键改进：添加DATE_THRESHOLD保护小数值
        boolean aboveThreshold = value >= DATE_THRESHOLD;

        return value >= MIN_EXCEL_DATE &&
                value <= MAX_EXCEL_DATE &&
                isNearInteger &&
                aboveThreshold; // 必须大于阈值
    }

    /**
     * 验证日期是否合理（1900-2100年）
     */
    private static boolean isValidDate(Date date) {
        if (date == null) return false;

        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int year = cal.get(Calendar.YEAR);

        return year >= 1900 && year <= 2100;
    }

    /**
     * 统一格式化日期
     */
    private static String formatDate(Date date) {
        return DATE_FORMAT.format(date);
    }

    // 业务层调用此方法获取项目结束日期
    public static String getProjectEndDate(Map<String, String> rowData, String planColumnPrefix) {
        // 1. 识别所有计划列
        List<String> planColumns = new ArrayList<>();
        for (String header : rowData.keySet()) {
            if (header.endsWith(planColumnPrefix)) {
                planColumns.add(header);
            }
        }

        // 2. 提取所有有效的计划日期
        List<Date> planDates = new ArrayList<>();
        for (String column : planColumns) {
            String dateStr = rowData.get(column);
            if (dateStr != null && isValidDateFormat(dateStr)) {
                try {
                    Date date = DATE_FORMAT.parse(dateStr);
                    planDates.add(date);
                } catch (Exception e) {
                    // 忽略解析异常
                }
            }
        }

        // 3. 计算最大日期
        if (!planDates.isEmpty()) {
            Date maxDate = Collections.max(planDates);
            return DATE_FORMAT.format(maxDate);
        }
        return null;
    }

    // 检查字符串是否符合日期格式
    private static boolean isValidDateFormat(String dateStr) {
        try {
            DATE_FORMAT.parse(dateStr);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取公式计算结果为字符串
     */
    private static String getFormulaResultAsString(Cell cell) {
        try {
            switch (cell.getCachedFormulaResultType()) {
                case STRING:
                    return cell.getStringCellValue();

                case NUMERIC:
                    // 对公式结果使用相同的数值处理逻辑
                    return handleNumericCell(cell);

                case BOOLEAN:
                    return String.valueOf(cell.getBooleanCellValue());

                default:
                    return cell.toString();
            }
        } catch (Exception e) {
            // 公式计算失败时返回原始公式
            return cell.getCellFormula();
        }
    }


    /**
     * 获取项目结束日期（带时间，格式为yyyy-MM-dd 23:59:59），若日期为周末则自动调整为下周一
     *
     * @param rowData         单行数据
     * @param planColumnPrefix 计划列前缀
     * @return 修正后的项目结束日期（格式化为当天23:59:59），如果没有有效日期返回null
     */
    public static String getProjectEndDateWithTime(Map<String, String> rowData, String planColumnPrefix) {
        // 1. 定义日期格式（复用避免重复创建）
        SimpleDateFormat baseDateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 基础日期格式（假设getProjectEndDateBase返回此格式）
        SimpleDateFormat endTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 目标格式

        // 2. 获取基础日期（不带时间，如2025-08-30）
        Date baseDate = getProjectEndDateBase(rowData, planColumnPrefix);
        if (baseDate == null) {
            return null;
        }

        // 3. 转换为Calendar，方便处理星期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(baseDate);

        // 4. 检查是否为周末（周六：Calendar.SATURDAY=7，周日：Calendar.SUNDAY=1）
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == Calendar.SATURDAY) {
            // 周六：加2天到下周一
            calendar.add(Calendar.DATE, 2);
        } else if (dayOfWeek == Calendar.SUNDAY) {
            // 周日：加1天到下周一
            Calendar c =getEndTimeOfPreviousProject(rowData,planColumnPrefix);
            if ( c!=null && c.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
                calendar.add(Calendar.DATE, 2);
            }else {
                calendar.add(Calendar.DATE, 1);
            }
        }
        // 非周末：不调整

        // 5. 设置时间为23:59:59
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 0); // 清除毫秒，避免格式问题

        // 6. 格式化并返回
        return endTimeFormat.format(calendar.getTime());
    }

    private static Calendar getEndTimeOfPreviousProject(Map<String, String> rowData, String planColumnPrefix) {
        // 1. 识别所有计划列
        List<String> planColumns = new ArrayList<>();
        for (String header : rowData.keySet()) {
            if (header.endsWith(planColumnPrefix)) {
                planColumns.add(header);
            }
        }

        // 2. 提取所有有效的计划日期
        List<Date> planDates = new ArrayList<>();
        for (String column : planColumns) {
            String dateStr = rowData.get(column);
            if (dateStr != null) {
                try {
                    // 尝试带时间解析
                    Date date = DATE_TIME_FORMAT.parse(dateStr);
                    planDates.add(date);
                } catch (Exception e1) {
                    try {
                        // 尝试不带时间解析
                        Date date = DATE_FORMAT.parse(dateStr);
                        planDates.add(date);
                    } catch (Exception e2) {
                        // 忽略无效日期格式
                    }
                }
            }
        }

        // 3. 计算最大日期
        if (!planDates.isEmpty()) {
            if (planDates.size() > 1){
                planDates.sort(Date::compareTo);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(planDates.get(planDates.size() - 2));
                return calendar;
            }
        }
        return null;

    }

    /**
     * 获取项目结束日期的基础Date对象
     */
    private static Date getProjectEndDateBase(Map<String, String> rowData, String planColumnPrefix) {
        // 1. 识别所有计划列
        List<String> planColumns = new ArrayList<>();
        for (String header : rowData.keySet()) {
            if (header.endsWith(planColumnPrefix)) {
                planColumns.add(header);
            }
        }

        // 2. 提取所有有效的计划日期
        List<Date> planDates = new ArrayList<>();
        for (String column : planColumns) {
            String dateStr = rowData.get(column);
            if (dateStr != null) {
                try {
                    // 尝试带时间解析
                    Date date = DATE_TIME_FORMAT.parse(dateStr);
                    planDates.add(date);
                } catch (Exception e1) {
                    try {
                        // 尝试不带时间解析
                        Date date = DATE_FORMAT.parse(dateStr);
                        planDates.add(date);
                    } catch (Exception e2) {
                        // 忽略无效日期格式
                    }
                }
            }
        }

        // 3. 计算最大日期
        if (!planDates.isEmpty()) {
            return Collections.max(planDates);
        }
        return null;
    }

    /**
     * 处理数值单元格（增强时间处理）
     */
    private static String handleNumericCell(Cell cell) {
        double numericValue = cell.getNumericCellValue();

        // 1. 处理日期时间值
        if (DateUtil.isCellDateFormatted(cell)) {
            Date date = cell.getDateCellValue();
            // 检查是否有时间部分
            if (hasTimePart(date)) {
                return DATE_TIME_FORMAT.format(date);
            }
            return DATE_FORMAT.format(date);
        }

        // 2. 处理可能的Excel日期值
        if (isPossibleExcelDate(numericValue)) {
            Date date = DateUtil.getJavaDate(numericValue);
            if (isValidDate(date)) {
                // 检查是否有时间部分
                if (hasTimePart(date)) {
                    return DATE_TIME_FORMAT.format(date);
                }
                return DATE_FORMAT.format(date);
            }
        }

        // 3. 普通数值处理
        return NumberToTextConverter.toText(numericValue);
    }

    /**
     * 检查日期是否包含时间部分（不只是00:00:00）
     */
    private static boolean hasTimePart(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.HOUR) != 0 ||
                cal.get(Calendar.MINUTE) != 0 ||
                cal.get(Calendar.SECOND) != 0 ||
                cal.get(Calendar.MILLISECOND) != 0;
    }

    /**
     * 获取     * 获取项目结束日期（带时间，格式为yyyy-MM-dd 23:59:59），若日期为周末则自动调整为下周一
     *
     * @param baseDateStr 基础日期字符串（格式必须为yyyy-MM-dd）
     * @return 修正后的调整后的项目结束日期（格式：yyyy-MM-dd HH:mm:ss），如果输入日期无效返回null
     */
    public static String getProjectEndDateWithTime(String baseDateStr) {
        // 1. 定义日期格式（复用避免重复创建）
        SimpleDateFormat baseDateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 输入日期格式
        SimpleDateFormat endTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 输出目标格式
        baseDateFormat.setLenient(false); // 严格校验日期格式，避免2025-13-01等无效日期

        // 2. 解析输入的日期字符串
        Date baseDate;
        try {
            baseDate = baseDateFormat.parse(baseDateStr);
        } catch (ParseException e) {
            // 日期格式无效（如非yyyy-MM-dd格式、无效日期）
            return null;
        }

        // 3. 转换为Calendar，方便处理星期和时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(baseDate);

        // 4. 检查是否为周末（周六：Calendar.SATURDAY=7，周日：Calendar.SUNDAY=1）
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == Calendar.SATURDAY) {
            // 周六：加2天到下周一
            calendar.add(Calendar.DATE, 2);
        } else if (dayOfWeek == Calendar.SUNDAY) {
            // 周日：加1天到下周一
            calendar.add(Calendar.DATE, 1);
        }
        // 非周末：不调整日期

        // 5. 设置时间为23:59:59
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 0); // 清除毫秒，避免格式问题

        // 6. 格式化并返回
        return endTimeFormat.format(calendar.getTime());
    }
}